package com.soul.sys.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.captcha.generator.MathGenerator;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.soul.common.bean.vo.BaseDataVo;
import com.soul.common.bean.vo.FileVo;
import com.soul.common.constant.CacheConstants;
import com.soul.common.enums.UserTypeEnum;
import com.soul.common.exception.BaseException;
import com.soul.common.msg.ResultEnum;
import com.soul.common.service.BaseDataService;
import com.soul.common.service.BaseService;
import com.soul.common.utils.FormatUtil;
import com.soul.common.utils.ListUtil;
import com.soul.common.utils.RedisCache;
import com.soul.sys.bean.bo.UserBo;
import com.soul.sys.bean.dto.LoginDto;
import com.soul.sys.bean.dto.RegisterUserDto;
import com.soul.sys.bean.dto.user.UserAddDto;
import com.soul.sys.bean.dto.user.UserSearchDto;
import com.soul.sys.bean.dto.user.UserUpdateDto;
import com.soul.sys.bean.po.UserPo;
import com.soul.sys.bean.vo.LoginVo;
import com.soul.sys.bean.vo.UserInfoVo;
import com.soul.common.bean.vo.UserVo;
import com.soul.sys.mapper.UserMapper;
import com.soul.sys.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author sws
 * @since 2022-11-23 01:06:23
 */
@Service
public class UserServiceImpl extends BaseService<UserMapper, UserPo> implements UserService {
    @Autowired
    private RedisCache redisCache;

    @Autowired
    private BaseDataService baseDataService;
    @Override
    public LoginVo login(LoginDto loginDto){
        // 验证图片验证码是否正确
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + loginDto.getUuid();
        String code = redisCache.getCacheObject(verifyKey);
        if (ObjectUtil.isEmpty(code)){
            throw new BaseException("验证码已过期");
        }
        MathGenerator mathGenerator = new MathGenerator(1);
        // 验证
        boolean verify = mathGenerator.verify(code, loginDto.getCode());
        if (!verify){
            throw new BaseException("验证码输入错误");
        }
        // 登录
        return loginToken(loginDto);
    }

    @Override
    public LoginVo loginToken(LoginDto loginDto) {
        // 登录
        UserBo userBo = new UserBo();
        userBo.setUsername(loginDto.getUsername());
        userBo.setPassword(loginDto.getPassword());
        // 根据用户名密码查询用户
        UserPo userPo = this.getLambadaQueryWrapper()
                .eq(UserPo::getUsername, userBo.getUsername())
                .eq(UserPo::getPassword, userBo.getPassword()).one();
        // 用户是否存在
        if (ObjectUtil.isEmpty(userPo)){
            throw new BaseException(ResultEnum.LOGIN_ERROR.getMsg());
        }
        // 登录成功，记录登录时间，登录ip
        LocalDateTime now = LocalDateTime.now();
        userPo.setLoginTime(now);
        userPo.setLoginIp(userBo.getHostIp());
        this.updateById(userPo);
        UserInfoVo userInfo = new UserInfoVo();
        BeanUtil.copyProperties(userPo,userInfo);
        // 生成token
        StpUtil.login(userPo.getId());
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        // 封装返回信息
        LoginVo loginVo = new LoginVo();
        loginVo.setTokenName(tokenInfo.getTokenName());
        loginVo.setTokenValue(tokenInfo.getTokenValue());
        loginVo.setUserInfo(userInfo);
        return loginVo;
    }

    @Override
    public void logout() {
        // 注销登录，当前会话
        StpUtil.logout();
    }

    @Override
    public UserInfoVo getLoginInfo() {
        // 获取当前登录人信息
        long id = StpUtil.getLoginIdAsLong();
        UserPo userPo = this.getById(id);
        UserInfoVo userInfoVo = BeanUtil.copyProperties(userPo, UserInfoVo.class);
        BaseDataVo baseDataVo = new BaseDataVo();
        baseDataVo.addFileId(userPo.getAvatarId());
        baseDataService.loadBaseData(baseDataVo);
        FileVo fileVo = baseDataVo.getFileVo(userPo.getAvatarId());
        if (ObjectUtil.isNotEmpty(fileVo)){
            userInfoVo.setAvatar(fileVo.getUrl());
        }
        return userInfoVo;
    }


    @Override
    public IPage<UserVo> queryUserList(Integer page, Integer size, UserSearchDto searchDto){
        LambdaQueryWrapper<UserPo> wrapper = this.lambadaQueryWrapper();
        if (ObjectUtil.isNotEmpty(searchDto)){
            wrapper.eq(ObjectUtil.isNotEmpty(searchDto.getUserType()),UserPo::getUserType,searchDto.getUserType())
                    .like(ObjectUtil.isNotEmpty(searchDto.getName()),UserPo::getName,searchDto.getName())
                    .like(ObjectUtil.isNotEmpty(searchDto.getUsername()),UserPo::getUsername,searchDto.getUsername())
                    .like(ObjectUtil.isNotEmpty(searchDto.getAge()),UserPo::getAge,searchDto.getAge())
                    .eq(ObjectUtil.isNotEmpty(searchDto.getSex()),UserPo::getSex,searchDto.getSex());
        }
        Page<UserPo> userPoPage = this.page(new Page<>(page, size), wrapper);
        BaseDataVo baseDataVo = baseDataService.loadBaseData(userPoPage.getRecords(), (t, b) -> {
            b.addDictType("sys.sex","sys.user.type");
        });
        return userPoPage.convert(t-> this.toDataVo(t,baseDataVo));
    }

    public UserVo toDataVo(UserPo userPo){
        return BeanUtil.copyProperties(userPo, UserVo.class);
    }
    public UserVo toDataVo(UserPo userPo,BaseDataVo baseDataVo){
        UserVo userVo = BeanUtil.copyProperties(userPo, UserVo.class);
        userVo.setSexVo(baseDataVo.getDictVo("sys.sex", FormatUtil.toString(userPo.getSex())));
        userVo.setUserTypeVo(baseDataVo.getDictVo("sys.user.type", userPo.getUserType()));
        FileVo fileVo = baseDataVo.getFileVo(userPo.getAvatarId());
        if (ObjectUtil.isNotEmpty(fileVo)){
            userVo.setAvatar(fileVo.getUrl());
        }
        return userVo;
    }

    @Override
    public void addUser(UserAddDto addDto){
        // 校验用户是否合法
        this.verifyUsername(addDto);
        UserPo userPo = BeanUtil.copyProperties(addDto, UserPo.class);
        // 新增的用户都是普通管理员
        userPo.setUserType("admin_user");
        // 排序号
        Long maxSort = this.getMaxSort();
        userPo.setSort(maxSort);
        this.save(userPo);
    }

    @Override
    public void updateUser(UserUpdateDto updateDto){
        UserPo userPo = this.getById(updateDto.getId());
        if (ObjectUtil.isEmpty(userPo)){
            throw new BaseException("数据已不存在");
        }
        // 校验用户是否合法
        this.verifyUsername(updateDto);
        BeanUtil.copyProperties(updateDto, userPo);
        // 排序号
        this.updateById(userPo);
    }

    @Override
    public void delUser(List<Long> ids){
        List<UserPo> userPos = this.listByIds(ids);
        if (!ObjectUtil.isEmpty(userPos)){
            for (UserPo userPo : userPos) {
                if (userPo.getUserType().equals(UserTypeEnum.USER.getCode())){
                    throw new BaseException("无法删除普通用户！");
                }
                if (userPo.getUserType().equals(UserTypeEnum.ADMIN.getCode())){
                    throw new BaseException("无法删除超级管理员！");
                }
            }
            this.removeBatchByIds(ids);
        }
    }

    private void verifyUsername(UserAddDto addDto) {
        if (ObjectUtil.isNotEmpty(addDto)){
            List<UserPo> userPos = this.getLambadaQueryWrapper()
                    .eq(UserPo::getUsername, addDto.getUsername())
                    .or().eq(UserPo::getEmail, addDto.getEmail()).list();
            if (ObjectUtil.isNotEmpty(userPos)){
                StringBuilder sb = new StringBuilder();
                for (UserPo userPo : userPos) {
                    if (ObjectUtil.equal(userPo.getUsername(),userPo.getEmail())){
                        if (sb.length() > 0){
                            sb.append("、");
                        }
                        sb.append("用户名不能重复");
                    }
                    if (ObjectUtil.equal(userPo.getEmail(),userPo.getEmail())){
                        if (sb.length() > 0){
                            sb.append("、");
                        }
                        sb.append("邮箱已经使用");
                    }
                }
                throw new BaseException(sb.toString());
            }
        }
    }
    private void verifyUsername(UserUpdateDto updateDto) {
        if (ObjectUtil.isNotEmpty(updateDto)){
            List<UserPo> userPos = this.getLambadaQueryWrapper()
                    .eq(UserPo::getUsername, updateDto.getUsername())
                    .or().eq(UserPo::getEmail, updateDto.getEmail()).ne(UserPo::getId,updateDto.getId()).list();
            if (ObjectUtil.isNotEmpty(userPos)){
                StringBuilder sb = new StringBuilder();
                for (UserPo userPo : userPos) {
                    if (ObjectUtil.equal(userPo.getUsername(),userPo.getEmail())){
                        if (sb.length() > 0){
                            sb.append("、");
                        }
                        sb.append("用户名不能重复");
                    }
                    if (ObjectUtil.isNotEmpty(updateDto.getEmail()) && ObjectUtil.equal(userPo.getEmail(),userPo.getEmail())){
                        if (sb.length() > 0){
                            sb.append("、");
                        }
                        sb.append("邮箱已经使用");
                    }
                }
                if (sb.length() > 0){
                    throw new BaseException(sb.toString());

                }
            }
        }
    }

    @Override
    public List<UserVo> queryUserByIds(Collection<Long> ids){
        List<UserPo> userPos = this.listByIds(ids);
        BaseDataVo baseDataVo = baseDataService.loadBaseData(userPos, (t, b) -> b.addFileId(t.getAvatarId()));
        return ListUtil.toValueList(userPos,t->this.toDataVo(t,baseDataVo));
    }

    /**
     * 注册用户
     * @param registerUserDto
     */
    @Override
    public void addRegisterUser(RegisterUserDto registerUserDto){
        if (ObjectUtil.isEmpty(registerUserDto.getUsername())){
            throw new BaseException("用户名不能为空");
        }
        List<UserPo> userPos = this.getLambadaQueryWrapper().eq(UserPo::getUsername, registerUserDto.getUsername()).list();
        if (ObjectUtil.isNotEmpty(userPos) && !userPos.isEmpty()){
            throw new BaseException("用户名已被使用！");
        }
        if (ObjectUtil.isNotEmpty(registerUserDto.getEmail())){
            List<UserPo> userPos2 = this.getLambadaQueryWrapper().eq(UserPo::getEmail, registerUserDto.getEmail()).list();
            if (ObjectUtil.isNotEmpty(userPos2) && !userPos2.isEmpty()){
                throw new BaseException("邮箱已被使用！");
            }
        }
        UserPo userPo = BeanUtil.copyProperties(registerUserDto, UserPo.class);
        // 排序号
        Long maxSort = this.getMaxSort();
        userPo.setSort(maxSort);
        this.save(userPo);
    }

    @Override
    public UserVo getInfoById(Long id){
        UserPo userPo = this.getById(id);
        UserVo dataVo = this.toDataVo(userPo);
        return dataVo;
    }
}
